package ui.list
{
	import com.GCInventory;
	import com.GCItem;
	import events.GCEvent;
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import ui.Scrollbar;
	import events.SliderEvent;
	import data.*;

	import flash.display.DisplayObjectContainer;
	import flash.display.Shape;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.geom.Point;
	import flash.text.TextField;
	import flash.utils.Dictionary;

	import com.greensock.TweenLite;
	import com.greensock.easing.Quad;
	
	public class ScrollList extends Sprite 
	{				
		// UI components
		protected var _background:Sprite;				// The sprite representing the background panel
		protected var _list:Sprite;						// Sprite holder containing the items
		protected var _menuMask:Shape;					// Masks the visible portions of the list
		protected var _scrollbar:Scrollbar;				// Scrollbar component
		
		// UI variables
		protected var componentHeight:Number;
		protected var componentWidth:Number;
        protected var verticalPadding:Number = 5;
        protected var itemHeight:Number = 60;
		protected var size:int;
		
		// Color Scheme
		protected var _defaultColor:uint 		= 0x000000;
		protected var _alternateColor:uint 		= 0xff0000;
		protected var _selectedColor:uint 		= 0xa4c639;
		protected var _rolloverColor:uint		= 0x0000ff;
		
		protected var _alternateRows:Boolean 	= false;
		
		// Extra		        
		protected var prevY:Number = 0;
        protected var listHeight:Number;
        protected var hitAreaHeight:Number;
        protected var listInitY:Number;
		protected var listHitArea:Shape;
		
		protected var scroll:Boolean = true;
		protected var selectIndex:int;

		// Shared with extended classes
		protected var _selected:GCItemListUI;				// The sales unit that the user has currently chosen
		protected var _displayList:Dictionary;			// A dictionary that holds all of the UI currently handled by this list	
		protected var _capacityText:TextField;
		protected var _dragBox:Sprite;
		
		// misc.
		protected var scrollOnMouseMove:Boolean = true;
		protected var listX:Number;
		protected var listY:Number;
		protected var showCapacity:Boolean;
		protected var topScrollBox:Shape;
		protected var bottomScrollBox:Shape;
		
		
		/**
		 * Constructor
		 */
		public function ScrollList(width:Number, height:Number, showCapacity:Boolean = false)
		{
			this.componentWidth = width;
			this.componentHeight = height;
			this.showCapacity = showCapacity;
			
			init();
		}
		
		/**
		 * Initializes the components
		 */
		private function init():void 
		{
			size = 0;
			
			// Listeners
			addEventListener(MouseEvent.MOUSE_OVER, handleRollOverList);
			addEventListener(MouseEvent.MOUSE_OUT, handleRollOutList);
			addEventListener(MouseEvent.MOUSE_WHEEL, onMouseWheel);
			
			// Setup the background
			_background = new Sprite();
			_background = GCResources.getMaskedPaperBackground(componentWidth, componentHeight);
			this.addChild(_background);
			
			// Setup the mask
			_menuMask = new Shape();
			_menuMask.graphics.clear();
			_menuMask.graphics.beginFill(0xFFFFFF, 0);
			_menuMask.graphics.drawRect(0, 0, componentWidth, componentHeight - 20);
			_menuMask.graphics.endFill();
			this.addChild(_menuMask);
			
			// Create the holder for the items
			_list = new Sprite();	
			_list.mask = _menuMask;		
			this.addChild(_list);					
			
			// Create the scrollbar
			_scrollbar = new Scrollbar(componentHeight);
			_scrollbar.x = componentWidth - _scrollbar.width;
			_scrollbar.addEventListener(SliderEvent.CHANGE, updateContent);
			//this.addChild(_scrollbar);
			
			// Create the hit area
			listHitArea = new Shape();
            listHitArea.graphics.clear();
            listHitArea.graphics.beginFill(0xFFFFFF,0);
            listHitArea.graphics.drawRect(0, 0, componentWidth, componentHeight - 20);			
            listHitArea.graphics.endFill();
            this.addChild(listHitArea);
			
            listInitY = _list.y;
            hitAreaHeight = listHitArea.height;	
			
			_capacityText = new TextField();
			if (showCapacity)
			{
				_capacityText.selectable = false;
				_capacityText.y = componentHeight - 20;
				_capacityText.height = 20;
				this.addChild(_capacityText);
			}

			_dragBox = new Sprite();
			//this.addChild(_dragBox);
			
			
			//000000000000000000000000000000000000000\
			
/*			topScrollBox = new Shape();
			topScrollBox.graphics.beginFill(0xff00ff, 1);
			//topScrollBox.graphics.drawRect(0, 0, componentWidth, componentHeight / 4);
			topScrollBox.graphics.endFill();
			this.addChild(topScrollBox);
			bottomScrollBox = new Shape();
			bottomScrollBox.graphics.beginFill(0xffff00, 1);
			//bottomScrollBox.graphics.drawRect(0, 0, componentWidth, componentHeight / 4);
			bottomScrollBox.graphics.endFill();
			bottomScrollBox.y = componentHeight - bottomScrollBox.height;
			this.addChild(bottomScrollBox);*/
			
			
            var point:Point = new Point(listHitArea.x, listHitArea.y);
                point = this.globalToLocal(point);

            listX = point.x;
            listY = point.y;
			//000000000000000000000000000000000000000000000000000000000000000
			
			
			
		}
		
		//----------------------------------------------------------------------
		//	PUBLIC FUNCTIONS
		//----------------------------------------------------------------------
		
		/**
		 * Removes all of the items that are in the list
		 */
		public function removeAll():void
		{
			if (_list.numChildren != 0) 
			{
				var i:int = _list.numChildren;
				while (i--) 
				{
					var item:Sprite = _list.getChildAt(i) as Sprite;
					item.removeEventListener(MouseEvent.ROLL_OVER, handleRollOverItem);
					item.removeEventListener(MouseEvent.ROLL_OUT, handleRollOutItem);					
                    item.removeEventListener(MouseEvent.MOUSE_DOWN, handleMouseDownItem);
                    item.removeEventListener(MouseEvent.MOUSE_UP, handleMouseDownItem);
					_list.removeChildAt(i);
					
				}
			}
			size = 0;
			_list.y = 0;
		}
		
		/**
		 * Realigns the UI components
		 */
		public function realign():void
		{
			_list.y = 0;
			for (var i:int = 0; i < size; i++ )
			{
				var item:Sprite = _list.getChildAt(i) as Sprite;
				item.x = verticalPadding;
				item.y = i*(verticalPadding + itemHeight);				
			}
		}
		
		/**
		 * Clear the selected
		 */
		public function clearSelecton():void
		{
			_selected = null;
		}
		
		/**
		 * Enables the scrolling
		 */
		public function scrollEnable():void
		{
			scroll = true;
		}
		
		/**
		 * Disables the scrolling
		 */
		public function scrollDisable():void
		{
			scroll = false;
		}
		
		
		//----------------------------------------------------------------------
		//	PRIVATE FUNCTIONS
		//----------------------------------------------------------------------
		
		/**
		 * Adds the new itemUI to the display
		 * @param	newItem
		 */
		protected function addDisplay(newItem:GCListUI):void
		{			
			// XY Positioning
			newItem.x = verticalPadding;
			newItem.y = size * (verticalPadding + itemHeight);
			
			// Add listeners to the UI
			newItem.addEventListener(MouseEvent.ROLL_OVER, handleRollOverItem);
			newItem.addEventListener(MouseEvent.ROLL_OUT, handleRollOutItem);
			newItem.addEventListener(MouseEvent.MOUSE_DOWN, handleMouseDownItem);
			newItem.addEventListener(MouseEvent.MOUSE_UP, handleMouseUpItem);		
			
			// Update the list properties
			size++;
			listHeight = size * (verticalPadding + itemHeight);
			
			// Add the UI to the list
			_list.addChild(newItem);
		}
		
		/**
		 * Removes the given itemUI from the display
		 * @param	itemUI
		 */
		protected function removeDisplay(itemUI:GCListUI):void
		{
			if (itemUI == null)
				return;
				
			// Check that the item is from this list
			if (_list != itemUI.parent)
				return;
			
			// Remove the listeners on the item
			itemUI.removeEventListener(MouseEvent.ROLL_OVER, handleRollOverItem);
			itemUI.removeEventListener(MouseEvent.ROLL_OUT, handleRollOutItem);
			itemUI.removeEventListener(MouseEvent.MOUSE_DOWN, handleMouseDownItem);
			itemUI.removeEventListener(MouseEvent.MOUSE_UP, handleMouseUpItem);
			
			// Remove the UI from the display
			_list.removeChild(itemUI);
			
			// Update the list properties
			size--;
			listHeight = size * (verticalPadding + itemHeight);
			
			// Unselect item
			_selected = null;
			
			// Realign the list
			realign();
		}		
		
		
		//----------------------------------------------------------------------
		//	Event Handlers
		//----------------------------------------------------------------------
		
		/**
		 * Handles moving the list when the scroll wheel moves
		 * @param	event
		 */
		protected function onMouseWheel(event:MouseEvent):void
		{		
			// The new location of the top of the list
			var newY:Number = _list.y + event.delta*15;
			// Difference between this and the previous Y			
			var del:Number = Math.abs(prevY - newY);
			
			// Check if scrolling is locked
			if (!scroll)
				return;
			
			if (del < 1) {
				_list.y = prevY;
				return;
			}
			
			// Don't scroll when there is not enough items in the list
			if (_list.height - 60 <= componentHeight) // TODO figure out where this 60 comes from --> list starts off with an initial height of 60
				return;
				
			// Check the boundaries			
			if(newY >= listInitY) {
                newY = listInitY;
            } else if (Math.abs(newY) > listHeight){
                newY = -listHeight;
            }

            prevY = _list.y;
            _list.y = newY;		
			_scrollbar.changeScroll( -event.delta);
		}
		
		protected function updateContent(event:SliderEvent):void
		{
			var scrollable:Number = _list.height - listInitY;
			_list.height = scrollable * event.percent;
			trace(event.percent);
		}
		
		/**
		 * Handles changing the appearance of an item when the mouse
		 * hovers over an item
		 * @param	event
		 */
		protected function handleRollOverItem(event:MouseEvent):void
        {
            event.target.alpha = .5;
        }

		/**
		 * Handles changing the appearance of an item back to 
		 * normal when the mouse is no longer hovering over the item
		 * @param	event
		 */
        protected function handleRollOutItem(event:MouseEvent):void
        {
            event.target.alpha = 1;
        }

		/**
		 * Handles the event when an item is clicked on
		 * @param	event
		 */
        protected function handleMouseDownItem(event:MouseEvent):void
        {
			scroll = false;
			
			// Change coloring of item			
			var object:GCItemListUI = event.currentTarget as GCItemListUI;
			// Show that the item is selected
			if (_selected != null)
				_selected.deselected();
			_selected = object;
			_selected.selected();
			
			// Drag the item
			//object.startDrag();
			//_selected.parent.removeChild(_selected);
			//_dragBox.addChild(object);
			
			// Store index and also make selected the top most
			//selectIndex = object.parent.getChildIndex(object);
			//object.parent.setChildIndex(object, size-1);
        }

		
		
		
		
		/**
		 * Handles the event when an item is released
		 * @param	event
		 */
        protected function handleMouseUpItem(event:MouseEvent):void
        {
            scroll = true;
			
			var object:Sprite = event.currentTarget as Sprite;
			var parent:Sprite = object.parent as Sprite;
			
			
			//object.stopDrag();
			//trace(event.)
			
			// Return the child to it's original index 
			//parent.setChildIndex(object, selectIndex);
			
			// Ease the object back to it's original position
			
			//var index:int = parent.getChildIndex(object);
			//var newX:Number = verticalPadding;
			//var newY:Number = index*(verticalPadding + itemHeight);
			//TweenLite.to(object, .1, {x:newX, y:newY, ease:Quad.easeOut});
			
			// Dispatch a selection event
			dispatchEvent(new GCEvent(GCEvent.LIST_ITEM_SELECTED_EVENT));
        }
		
		/**
		 * Handles adding the mouse move listener when mouse enters this display
		 * @param	event
		 */
		protected function handleRollOverList(event:MouseEvent):void
		{
			this.addEventListener(Event.ENTER_FRAME, handleMouseMoveList);
		}
		
		/**
		 * Handles removing the mouse move listener when the mouse leaves this display
		 * @param	event
		 */
		protected function handleRollOutList(event:MouseEvent):void
		{
			this.removeEventListener(Event.ENTER_FRAME, handleMouseMoveList);
		}		
		/**
		 * Updates the list's position based on the position of the mouse
		 * @param	event
		 */
		protected function handleMouseMoveList(event:Event):void
		{
			var x:Number = this.mouseX + Math.abs(listX);
            var y:Number = this.mouseY + Math.abs(listY);
			
			// Check to see if the mouse is in the top or bottom portion
			if (scroll && (y < componentHeight / 5 || y > (componentHeight - componentHeight / 5)) && x < componentWidth - 50)
			{
				blah(y);
			}
		}
		
		protected function blah(y:Number):void
		{
			var distance:Number = Math.cos( ( -(y + listY)/hitAreaHeight)*Math.PI )*15;
            var currentY:Number = _list.y;
			
            if ( (currentY + distance - verticalPadding) > listInitY + verticalPadding) return;
			
			// The new location of the top of the list
			var newY:Number = _list.y + distance;
			// Difference between this and the previous Y			
			var del:Number = Math.abs(prevY - newY);
				
			if (del < 1) {
				_list.y = prevY;
				return;
			}
			
			// Don't scroll when there is not enough items in the list
			if (listHeight <= componentHeight) // TODO figure out where this 60 comes from --> list starts off with an initial height of 60
				return;
				
			// Check the boundaries			
			if(newY >= listInitY) {
                newY = listInitY;
            } else if (Math.abs(newY) > listHeight - hitAreaHeight){
                newY = -(listHeight - hitAreaHeight);
            }
			
			prevY = _list.y;
            //_list.y = newY;		
			TweenLite.to(_list, .01, {y:newY, ease:Quad.easeOut});
		}		
		
		

		
        private function scrollEnterFrame(y:Number):void
        {
            var distance:Number = Math.cos( ( -(y + listY)/hitAreaHeight)*Math.PI )*15;
            var currentY:Number = _list.y;
            var newY:Number;

            if( (currentY + distance - verticalPadding) > listInitY + verticalPadding) return;

            newY = _list.y + distance;

            var delta:Number = Math.abs(prevY - newY);

            if(delta < 1) {
                _list.y = prevY;
                return;
            }

            if(newY >= listInitY) {
                newY = listInitY;
            } else if (Math.abs(newY) > listHeight){
                newY = -listHeight;
            }
			
			prevY = _list.y;
            _list.y = newY;
        }
		

		private function handleMouseMove(event:MouseEvent):void
        {
            var x:Number = this.mouseX + Math.abs(listX);
            var y:Number = this.mouseY + Math.abs(listY);
			
            if( _menuMask.hitTestPoint( x, y )  && scroll) {
                scrollMouseMove(y - Math.abs(listY));
            }
        }		
		
		private function scrollMouseMove(y:Number):void
        {
            var percent:Number = y/hitAreaHeight;
            var newY:Number = -(Math.round(listHeight*percent));

            if(newY + itemHeight*3 > hitAreaHeight) {
                newY = hitAreaHeight;
            } else if (newY + itemHeight*3 > listInitY) {
                newY = listInitY;
            }

            TweenLite.to(_list, 2, {y:newY, ease:Quad.easeOut});
        }
		
		
		//----------------------------------------------------------------------
		//	GET FUNCTIONS
		//----------------------------------------------------------------------
		
		/**
		 * Returns the currently selected itemUI
		 */
		public function get selected():GCItemListUI
		{
			return _selected;
		}	
		
	}
}